/*
 * Copyright 2008-2010 Daniel Cachapa <cachapa@gmail.com>
 * 
 * This program is distributed under the terms of the GNU General Public License Version 3
 * The license can be read in its entirety in the LICENSE.txt file accompanying this source code,
 * or at: http://www.gnu.org/copyleft/gpl.html
 * 
 * This file is part of Libra.
 *
 * WeightWatch is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * WeightWatch is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with the WeightWatch source code. If not, see: http://www.gnu.org/licenses
 */

package net.cachapa.libra.adapter;

import java.util.Vector;

import net.cachapa.libra.Main;
import net.cachapa.libra.R;
import net.cachapa.libra.chart.Chart;
import net.cachapa.libra.chart.DateImageGenerator;
import net.cachapa.libra.data.Database;
import net.cachapa.libra.data.Value;
import net.cachapa.libra.util.MyDate;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.Paint.Align;
import android.graphics.drawable.BitmapDrawable;
import android.os.AsyncTask;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Gallery;
import android.widget.ImageView;

public class ChartImageAdapter extends BaseAdapter {
	private static final int SEPARATOR = 10;
	
	private Context context;
	private int width, height;
	private int chartType;
	private Vector<ImageView> chartViews;
	private Vector<MyDate> dates;
	private Bitmap loadingBitmap;
	
	public ChartImageAdapter(Context context, int width, int height, int chartType) {
		this.context = context;
		this.width = width;
		this.height = height;
		this.chartType = chartType;
		
		chartViews = new Vector<ImageView>();
		dates = new Vector<MyDate>();
		
		loadingBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
		Paint paint = new Paint();
		paint.setColor(0xffffffff);
		paint.setAntiAlias(true);
		paint.setTextSize(20);
		paint.setTextAlign(Align.CENTER);
		Canvas canvas = new Canvas (loadingBitmap);
		canvas.drawText(context.getString(R.string.loading), width/2, height/2, paint);
	}
	
	public void addChart(MyDate date) {
		chartViews.add(null);
		if (date == null) {
			dates.add(null);
		}
		else {
			dates.add(new MyDate(date));
		}
	}
	
	public Bitmap generateLabeledChart(MyDate date, boolean background) {
		Bitmap labeledChart = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
		Canvas canvas = new Canvas(labeledChart);
		
		float scale;
		if (background) {
			canvas.drawRect(0 ,0 ,width ,height , new Paint());
			scale = 1;
		}
		else {
			scale = context.getResources().getDisplayMetrics().density;
		}
		
		MyDate startDate, endDate;
		Bitmap label = null;
		switch (chartType) {
		case Main.CHART_TYPE_WEEK:
			label = DateImageGenerator.GenerateImage(date, DateImageGenerator.TYPE_WEEK_YEAR, scale);
			break;
		case Main.CHART_TYPE_MONTH:
			label = DateImageGenerator.GenerateImage(date, DateImageGenerator.TYPE_MONTH_YEAR, scale);
			break;
		case Main.CHART_TYPE_30_DAY:
			endDate = new MyDate();
			startDate = new MyDate(endDate);
			startDate.addDays(-30);
			label = DateImageGenerator.GenerateImage(startDate, endDate, scale);
			break;
		case Main.CHART_TYPE_YEAR:
			label = DateImageGenerator.GenerateImage(date, DateImageGenerator.TYPE_YEAR, scale);
			break;
		case Main.CHART_TYPE_COMPLETE:
			Database database = Database.getInstance(context);
			if (database.isEmpty()) {
				startDate = new MyDate();
				endDate = new MyDate();
			}
			else {
				startDate = database.getFirstValue().getDate();
				endDate = database.getLatestValue().getDate();
			}
			label = DateImageGenerator.GenerateImage(startDate, endDate, scale);
			break;
		}
		
		Bitmap chart = generateChart(date, label.getHeight() + SEPARATOR, scale);
		
		canvas.drawBitmap(label, (width / 2) - (label.getWidth() / 2), 0, null);
		canvas.drawBitmap(chart, 0, label.getHeight() + SEPARATOR, null);
		
		return labeledChart;
	}

	private Bitmap generateChart(MyDate date, int labelHeight, float scale) {
		Database database = Database.getInstance(context);
		
		Vector<Value> values = null;
		MyDate startDate = null;
		MyDate endDate = null;
		switch (chartType) {
		case Main.CHART_TYPE_WEEK:
			startDate = new MyDate(date);
			startDate.backToFirstDayOfWeek();
			endDate = new MyDate(startDate);
			endDate.addDays(7);
			values = database.getPeriod(startDate, endDate, Database.ORDER_ASC);
			break;
		case Main.CHART_TYPE_MONTH:
			values = database.getMonth(date, Database.ORDER_ASC);
			startDate = new MyDate(date.getYear(), date.getMonth(), 1);
			endDate = new MyDate(date.getYear(), date.getMonth(), date.getDaysInMonth());
			break;
		case Main.CHART_TYPE_30_DAY:
			endDate = new MyDate();
			startDate = new MyDate(endDate);
			startDate.addDays(-30);
			values = database.getPeriod(startDate, endDate, Database.ORDER_ASC);
			break;
		case Main.CHART_TYPE_YEAR:
			values = database.getYear(date, Database.ORDER_ASC);
			startDate = new MyDate(date.getYear(), 1, 1);
			endDate = new MyDate(date.getYear(), 12, 31);
			break;
		case Main.CHART_TYPE_COMPLETE:
			values = database.getAllValues(Database.ORDER_ASC);
			if (values.isEmpty()) {
				startDate = new MyDate();
				endDate = new MyDate();
			}
			else {
				startDate = new MyDate(values.firstElement().getDate());
				endDate = new MyDate(values.lastElement().getDate());
			}
			break;
		}
		
		// Now get the values immediately before and after the retrieved values and add them to the collection
		Value value = database.getValueBefore(startDate);
		if (value != null) {
			values.add(0, value);
		}
		value = database.getValueAfter(endDate);
		if (value != null) {
			values.add(value);
		}
		
		return (new Chart()).generateChart(width, height - labelHeight, values, startDate, endDate, context, scale);
	}

	public int getCount() {
		return dates.size();
	}

	public Object getItem(int position) {
		return position;
	}

	public long getItemId(int position) {
		return position;
	}

	public View getView(int position, View convertView, ViewGroup parent) {
		return getChartView(position);
//		ChartView chartView = new ChartView(context);
//		return chartView;
	}
	
	private ImageView getChartView(int position) {
		ImageView chartView;
		// Check if an ImageView already exists in the vector
		if (chartViews.get(position) != null) {
			chartView = chartViews.get(position);
		}
		else {
			// If it doesn't, then we generate a new ImageView, set it to show a progress image 
			chartView = new ImageView(context);
			chartView.setLayoutParams(new Gallery.LayoutParams(width + 50, height));
			chartView.setScaleType(ImageView.ScaleType.CENTER);
			chartView.setImageBitmap(Bitmap.createBitmap(loadingBitmap));
			chartViews.setElementAt(chartView, position);
			// Now we start generating a new chart for it in the background
			ChartGenerator cg = new ChartGenerator();
			cg.execute(position);
		}
		// Return the ImageView
		return chartView;
	}

	public MyDate getDate(int position) {
		return dates.get(position);
	}
	
	public int getPosition(MyDate date) {
		int size = dates.size();
		switch (chartType) {
		case Main.CHART_TYPE_WEEK:
			MyDate weekDate = new MyDate(date);
			weekDate.backToFirstDayOfWeek();
			for (int i = 0; i < size; i++) {
				if (dates.get(i).equals(weekDate)) {
					return i;
				}
			}
			
		case Main.CHART_TYPE_MONTH:
			for (int i = 0; i < size; i++) {
				if (dates.get(i).getMonth() == date.getMonth() && dates.get(i).getYear() == date.getYear()) {
					return i;
				}
			}
			
		case Main.CHART_TYPE_YEAR:
			for (int i = 0; i < size; i++) {
				if (dates.get(i).getYear() == date.getYear()) {
					return i;
				}
			}
			
		}
		return 0;
	}

	public void clear() {
		chartViews.clear();
		dates.clear();
	}
		
	private class ChartGenerator extends AsyncTask<Integer, Object, Bitmap> {
		private int position;

		protected Bitmap doInBackground(Integer... params) {
			position = params[0].intValue();
			Bitmap chart = generateLabeledChart(dates.get(position), false);
			return chart;
		}
		
		protected void onPostExecute(Bitmap result) {
			ImageView chartView = chartViews.get(position);
			Bitmap chart = ((BitmapDrawable)chartView.getDrawable()).getBitmap();
			Canvas canvas = new Canvas(chart);
			//Erases the canvas
			canvas.drawColor(0, PorterDuff.Mode.CLEAR);
			
			canvas.drawBitmap(result, 0, 0, null);
			chartView.invalidate();
		}
	}
}